package com.junmeng.libfloating.widget

import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.junmeng.libfloating.R
import com.junmeng.libfloating.widget.LogRecyclerView.LogType.Companion.DEFAULT
import com.junmeng.libfloating.widget.LogRecyclerView.LogType.Companion.ERROR
import com.junmeng.libfloating.widget.LogRecyclerView.LogType.Companion.INFO
import java.util.*

class LogRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
    annotation class LogType {
        companion object {
            const val DEFAULT: Int = -1
            const val INFO: Int = 3
            const val ERROR: Int = 5
        }
    }

    private var myAdapter: MyAdapter? = null
    private val logContents: MutableList<LogContent> = ArrayList()
    private fun init(context: Context) {
        layoutManager = LinearLayoutManager(context)
        adapter = MyAdapter().also { myAdapter = it }
        itemAnimator = null
    }

    fun appendInfo(log: String) {
        appendLog(log, INFO)
    }

    fun appendError(log: String) {
        appendLog(log, ERROR)
    }

    fun appendLog(log: String, @LogType level: Int) {
        lateinit var logContent: LogContent
        when (level) {
            INFO -> LogContent(level = INFO, log = log)
            else -> LogContent(level = DEFAULT, log = log)
        }
        appendLog(logContent)
    }

    fun appendLog(logContent: LogContent) {
        val isBottom = isBottom()
        logContents.add(logContent)
        myAdapter!!.notifyItemChanged(logContents.size - 1)
        if (isBottom) {
            smoothScrollToPosition(logContents.size - 1)
        }
    }

    fun appendLogs(logs: List<String>, @LogType level: Int) {
        if (logs.isEmpty()) {
            return
        }
        appendLogs(logs.map {
            LogContent(log = it, level = level)
        })
    }

    fun appendLogs(logs: List<LogContent>) {
        if (logs.isEmpty()) {
            return
        }
        val isBottom = isBottom()
        val oldSize = logContents.size
        logContents.addAll(logs)
        myAdapter?.notifyItemRangeChanged(oldSize, logs.size)
        if (isBottom) {
            smoothScrollToPosition(logContents.size - 1)
        }
    }

    /**
     * 判断当前是否在底部
     */
    fun isBottom() = !canScrollVertically(1)

    /**
     * 滑动到底部
     */
    fun smoothScrollToEnd() {
        if (logContents.isNotEmpty()) {
            smoothScrollToPosition(logContents.size - 1)
        }
    }

    /**
     * 清空日志
     */
    fun clearLog() {
        logContents.clear()
        myAdapter!!.notifyDataSetChanged()
    }

    internal inner class MyAdapter : Adapter<MyViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            return MyViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.floating_item_log, parent, false)
            )
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.logTextView.text = logContents[position].log
            var colorInt = Color.WHITE
            when (logContents[position].level) {
                DEFAULT -> colorInt = Color.WHITE
                INFO -> colorInt = Color.YELLOW
                ERROR -> colorInt = Color.RED
                else -> colorInt = Color.WHITE
            }
            holder.logTextView.setTextColor(colorInt)
        }

        override fun getItemCount(): Int {
            return logContents.size
        }
    }

    internal inner class MyViewHolder(itemView: View) : ViewHolder(itemView) {
        var logTextView: TextView = itemView.findViewById(R.id.log)
    }

    data class LogContent(
        @LogType
        var level: Int = DEFAULT,
        var log: String? = null
    )

    init {
        init(context)
    }
}